package com.example.config.security;
import com.example.config.security.authentication.JwtAuthenticationTokenFilter;
import com.example.config.security.authentication.MenuAuthenticationFilter;
import com.example.config.security.authority.SecurityMetadataSourceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import javax.annotation.Resource;

/**
 * security配置类
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;//用户登录验证策略

    @Resource
    private PasswordEncoder passwordEncoder;//加密策略

    @Resource
    private AuthenticationEntryPoint authenticationEntryPoint;//用户未登录处理

    @Resource
    private AccessDeniedHandler accessDeniedHandler;//权限不足处理器

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;//jwt验证过滤器

    @Resource
    private MenuAuthenticationFilter menuAuthenticationFilter;

    @Resource
    private SecurityMetadataSourceImpl securityMetadataSource;//自定义权限配置

    @Resource
    private AccessDecisionManager accessDecisionManager;//访问决策

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //1.关闭csrf 跨域访问保护，开始跨域访问
        // 开启跨域配置
        http.cors()
                .and()
                .csrf().disable();
        //2.资源拦截
        http
                // [1]放行资源
                .authorizeRequests().antMatchers().permitAll()
                // [2]除了开放资源，所有资源都需要登录以后才可以访问（登录才可访问的资源）
                .anyRequest().authenticated()
                // 动态权限配置
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O obj) {
                        obj.setSecurityMetadataSource(securityMetadataSource);
                        obj.setAccessDecisionManager(accessDecisionManager);
                        return obj;
                    }
                });
        //4.自定义权限不足
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .authenticationEntryPoint(authenticationEntryPoint);

        //3.使用jwt验证不需要使用Session，关闭Session生成策略。
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //添加jwt 登录授权过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(menuAuthenticationFilter, JwtAuthenticationTokenFilter.class);

//记住我
//        http.rememberMe()
//                .tokenRepository(persistentTokenRepository)
//                .userDetailsService(userDetailsService)
//                .tokenValiditySeconds(7*24*60*60);//记住我，有效时长一周
//                .and();
//禁用缓存
//                .headers()
//                .cacheControl();
    }

    //不走Security的验证过滤器
    @Override
    public void configure(WebSecurity web) throws Exception {
        //不用通过拦截器的的请求路径
        String[] excludePattern = {
                "/login",
                "/logout",
                "/captcha",
                "/css/**",//css
                "/js/**",//js
                "/webjars/**",
                "/index.html",
                "favicon.icon",
                "/doc.html",//Swagger文档
                "/swagger-resources/**",
                "/v2/api-docs/**",
                "/swagger-ui.html",
                "/chat",
//                "/**"
        };
        web.ignoring().antMatchers(excludePattern).antMatchers(HttpMethod.OPTIONS);
    }
}
